/*
 * logic.c
 *
 * Created: 2012.11.23. 19:30:12
 *  Author: some00
 */ 
#include "logic.h"
#include <string.h>

//NULL terminated string of partial UART command
volatile char commandIn[41];
unsigned int lastVolume;

volatile Buffer buffer = { {} , 0, 0};

static char ButtonStrings[37][16] = 
{
		"button_on_off",
		"button_mute",
		"button_1",
		"button_2",
		"button_3",
		"button_4",
		"button_5",
		"button_6",
		"button_7",
		"button_8",
		"button_9",
		"button_i",
		"button_0",
		"button_epg",
		"button_vol_up",
		"button_vol_down",
		"button_menu",
		"button_txt",
		"button_p_plus",
		"button_p_minus",
		"button_up",
		"button_left",
		"button_right",
		"button_down",
		"button_ok",
		"button_exit",
		"button_opt",
		"button_red",
		"button_green",
		"button_yellow",
		"button_blue",
		"button_msg",
		"button_tv_stb",
		"button_unknown",
		"button_tv_r",
		"repeat",
		"invalid"
};

void InitLogic()
{
	lastVolume = 0x00;
	commandIn[0] = NULL;
}

int ButtonToAddress(Button b)
{
	if ( button_up == b)		return 0x10;
	if ( button_down == b)		return 0x10;
	
	if ( button_left == b)		return 0x12;
	if ( button_right == b)		return 0x12;
	
	if ( button_mute == b)		return 0x62;
	if ( button_vol_down == b)	return 0x62;
	if ( button_vol_up == b)	return 0x62;
	
	if ( button_txt == b)		return 0x86;
	
	if ( button_i == b)			return 0xE9;
	
	if ( button_menu == b)		return 0xDC;
	
	if ( button_p_minus == b)	return 0x60;
	if ( button_p_plus == b)	return 0x60;
	
	return -1;
}

typedef enum ButtonTypeS
{
	continuous,
	state
}ButtonType;


int getNextValueContinuous(int lastValue, Button b)
{
	int nextValue = lastValue;
	
	if ( button_up == b)		
	{
		nextValue += DELTA_BRIGHTNESS;
		if (nextValue > 100) nextValue = 100;
	}		
	if ( button_right == b)
	{
		nextValue += DELTA_CONTRAST;
		if (nextValue > 100) nextValue = 100;
	}		
	if ( button_vol_up == b)
	{
		nextValue += DELTA_VOLUME;
		if (nextValue > 100) nextValue = 100;
	}		
	
	if ( button_down == b)
	{
		nextValue -= DELTA_BRIGHTNESS;
		if (nextValue <= 0) nextValue = 0;	
	}
	
	if ( button_left == b)
	{
		nextValue -= DELTA_CONTRAST;
		if (nextValue <= 0) nextValue = 0;	
	}	
	if ( button_vol_down == b)	
	{
		nextValue -= DELTA_VOLUME;
		if (nextValue <= 0) nextValue = 0;	
	}
	
	//USART_Transmit('V');
	//USART_putInt(lastValue);
	//USART_putInt(nextValue);
	//USART_Transmit('\n');
	
	return nextValue;
}

int getNextValueState(int lastValue, Button button)
{
	//somewhere  deep in the memory there might be a hidden, magical place for this
	if(button == button_mute)
	{
		if(lastValue == 0x00) return lastVolume;
		else
		{
			lastVolume = lastValue;
			return 0x00;
		}
	}
	if(button == button_txt)
	{
		if(lastValue == 0x02) return 0x08;
		else return 0x02;
	}
	if(button == button_i)
	{
		if(lastValue == 0x02) return 0x00;
		else return 0x02;
	}
	if(button == button_menu)
	{
		switch(lastValue)
		{
			case 0x00: return 0x05;
			case 0x02: return 0x00;
			case 0x05: return 0x02;
			default: break;
		}
	}
	if(button == button_p_plus)
	{
		switch(lastValue)
		{
			case 0x01: return 0x11;
			case 0x11: return 0x12;
			case 0x12: return 0x01;
			default: break;
		}
	}
	if(button == button_p_minus)
	{
		switch(lastValue)
		{
			case 0x01: return 0x12;
			case 0x11: return 0x01;
			case 0x12: return 0x11;
			default: break;
		}
	}
	
	return -1;
}

ButtonType getButtonType(Button b)
{
	if ( button_up == b)		return continuous;
	if ( button_down == b)		return continuous;
	
	if ( button_left == b)		return continuous;
	if ( button_right == b)		return continuous;
	
	if ( button_mute == b)		return state;
	if ( button_vol_down == b)	return continuous;
	if ( button_vol_up == b)	return continuous;
	
	if ( button_txt == b)		return state;
	
	if ( button_i == b)			return state;
	
	if ( button_menu == b)		return state;
	
	if ( button_p_minus == b)	return state;
	if ( button_p_plus == b)	return state;
	
	return -1;
}

int repeatTypeButton(Button b)
{
	if (b == button_vol_down) return 1;
	if (b == button_vol_up) return 1;
	
	if (b == button_up) return 1;
	if (b == button_down) return 1;
	if (b == button_left) return 1;
	if (b == button_right) return 1;
	
	return 0;
}

Operation nextOp(Operation last)
{
	Operation next;
	
	next.address	= last.address;
	next.button		= last.button;
	next.callback	= last.callback;
	next.FlashType	= last.FlashType;
	next.OpType		= 'W';
	
	
	//next value
	ButtonType bt = getButtonType(last.button);
	
	switch(bt)
	{
		case -1:			next.value = last.value;
		case continuous:	next.value = getNextValueContinuous(last.value, last.button); break;
		case state:			next.value = getNextValueState(last.value, last.button); break;
	}
	
	return next;
}

void callBackFunction(Operation op)
{
	
	if (op.OpType == 'R')
	{
		Operation next = nextOp(op);
		
		for(int i = 0; ButtonStrings[op.button][i] != NULL; i++) USART_Transmit(ButtonStrings[op.button][i]);
		USART_Transmit(' ');
		USART_putInt(next.value);
		USART_Transmit('\r');
		USART_Transmit('\n');
		
		bufferAdd(next);
	}
}


int bufferAdd(Operation op)
{
	cli();
	//buffer full?
	if(buffer.write + 1 == buffer.read || buffer.read == 0 && buffer.write + 1 == BUFFER_SIZE)
	{
		sei();
		return 0;
	}		
	
	//store data
	buffer.data[buffer.write] = op;
	
	//set write
	buffer.write++;
	if (buffer.write >= BUFFER_SIZE) buffer.write = 0;
	
	//USART_Transmit('A');
	//USART_putInt( abs(buffer.write - buffer.read) );
	//USART_Transmit('\n');
	
	sei();
	return 1;
}

int bufferGet(Operation *op)
{
	cli();
	//buffer empty?
	if (buffer.read == buffer.write)
	{
		sei();
		return 0;
	}		
	
	*op = buffer.data[buffer.read];
	
	//set read
	buffer.read++;
	if (buffer.read >= BUFFER_SIZE) buffer.read = 0;
	
	//USART_Transmit('G');
	//USART_putInt( abs(buffer.write - buffer.read) );
	//USART_Transmit('\n');
	
	sei();
	return 1;
}

int bufferEmpty()
{
	if (buffer.read == buffer.write) return 1;
	else return 0;
}

Button stringToButton()
{
	for(Button b = 0; b <= invalid; b++)
	{
		if(0 == strcmp(commandIn, ButtonStrings[b])) return b;
	}
	return invalid;
}

void AddUartButton()
{
	char charIn[2];
	
	if(USART_Receive(&charIn[0]))
	{
		//if terminated add to operation buffer
		if(charIn[0] == '\n' || charIn[0] == '\r')
		{
			//button from string
			Button pressed = stringToButton();
			
			//create op
			Operation op;	
			op.address = ButtonToAddress(pressed);
			op.button = pressed;
			op.callback = &callBackFunction;
			if(pressed == button_on_off) op.FlashType = 'E';
			else op.FlashType = 'D';		//ddc			
			op.OpType = 'R';
			op.value = 0;
			
			//add op to buffer
			bufferAdd(op);
			
			//reset command
			commandIn[0] = NULL;
		}	
		//if not terminated add this character		
		else
		{
			charIn[1] = NULL;
			strcat(commandIn, charIn);
		}
	}
}